package org.ccay.core.util;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import org.ccay.core.exception.impl.CommonSystemException;


/**
 * json与xml互转工具类。
 * 
 * 本工具有如下特点：
 * 1、必须使用标准的json格式，key和字符串类型的value均需要加双引号
 * 2、支持转换包含list的json（即带[...]的json格式）
 * 3、转换前后的json与xml标签顺序一致（不会出现随机排序的情况）
 * 4、比较精准的报错提示
 * 
 *
 */
public class JsonXmlUtil {

	/**
	 * 常量XML_LIST_ATTRIBUTE和XML_LIST_TAG，作为JSON转成XML格式的保留字
	 * 例：转换{"people":[{"firstName":"Brett","lastName":"McLaughlin"}, {"firstName":"Jason","lastName":"Hunter"}]}
	 *    结果为<people isList="true">
	 *     			<listKeepWord><firstName>Brett</firstName><lastName>McLaughlin</lastName></listKeepWord>
	 *     			<listKeepWord><firstName>Jason</firstName><lastName>Hunter</lastName></listKeepWord>
	 *    	   </people>
	 */
	private static final String XML_LIST_ATTRIBUTE = "isList";
	private static final String XML_LIST_TAG = "listKeepWord";

//	public static void main(String[] args) throws DocumentException, IOException {
////		String jsonStr = "{ \"people\":[ {\"firstName\":[ {\"firstName\":\"Brett\",\"lastName\":\"McLaughlin\",\"email\":\"aaaa\"}, {\"firstName\":\"Jason\",\"lastName\":\"Hunter\",\"email\":\"bbbb\"} ],\"lastName\":\"McLaughlin\",\"email\":\"aaaa\"}, {\"firstName\":\"Jason\",\"lastName\":\"Hunter\",\"email\":\"bbbb\"}, {\"firstName\":\"Elliotte\",\"lastName\":\"Harold\",\"email\":\"cccc\"} ] }";
////		String jsonStr = "{\"工1中a是是A中是\":[{\"firstName\":\"是A中是\",\"lastName\":\"工1中a是是A中是\"}, {\"firstName\":\"Jason\",\"lastName\":\"Hunter\"}]}";
//
////		System.out.println(jsonStr);
////		String xmlStr = jsonToXml(jsonStr);
////		System.out.println(xmlStr);
////		System.out.println(xmlToJson(xmlStr));
//
////		String xmlStr = "<key1>value1</key1><key2>value2</key2><key3><inkey31><inkey311>invalue311</inkey311><inkey312>invalue312</inkey312></inkey31><inkey32>invalue32</inkey32></key3><key4><inkey41>invalue41</inkey41><inkey42>invalue42</inkey42></key4>";
////		System.out.println(xmlStr);
////		String jsonStr = xmlToJson(xmlStr);
////		System.out.println(jsonStr);
//
//		String jsonStr = "{\"key1\":1231311.89071,\"key2\":\"value2\",\"key3\":{\"inkey31\":{\"inkey311\":\"invalue311\",\"inkey312\":\"invalue312\"},\"inkey32\":\"invalue32\"},\"key4\":{\"inkey41\":\"invalue41\",\"inkey42\":\"invalue42\"}}";
//		System.out.println(jsonStr);
//		String xmlStr = jsonToXml(jsonStr);
//		System.out.println(xmlStr);
//		System.out.println(xmlToJson(xmlStr));
//	}

	/**
	 * xml转成json
	 * @param xmlStr	xml格式字符串
	 * @return			json格式字符串
	 * @throws DocumentException
	 * @throws IOException
	 */
	public static String xmlToJson(String xmlStr) throws DocumentException, IOException {
		Document document = DocumentHelper.parseText(new StringBuffer().append("<root>").append(xmlStr).append("</root>").toString());
		Map<String, Object> jsonMap = new LinkedHashMap<String, Object>();
		Element rootElm = document.getRootElement();
		//迭代根节点,将节点添加到map中
		xmlToJsonMap(rootElm, jsonMap);
		return JsonUtil.getJsonString(jsonMap);
	}

	/**
	 * 迭代xml节点到map中
	 * @param elm		迭代的xml节点
	 * @param jsonMap	装载结果的map容器
	 */
	@SuppressWarnings("unchecked")
	private static void xmlToJsonMap(Element elm, Map<String, Object> jsonMap) {
		for (Iterator<Element> it = (Iterator<Element>) elm.elementIterator(); it.hasNext();){
			Element element = (Element) it.next();
			String eleName = element.getName();
			//判断是list节点
			if (Boolean.valueOf(element.attributeValue(XML_LIST_ATTRIBUTE))) {
				List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
				//进入list迭代
				xmlToJsonList(element, list);
				//含有list属性却没有任何标签节点，则xml格式错误
				if (list.isEmpty()) {
					StringBuffer errMsg = new StringBuffer();
					errMsg.append("xml to json error. <").append(elm.getName()).append(" ").append(XML_LIST_ATTRIBUTE).append("=\"true\"> the list is empty.");
					throw new CommonSystemException(errMsg.toString());
				}
				jsonMap.put(eleName, list);
			} else if (element.isTextOnly()) {
				//处理文本
				jsonMap.put(eleName, element.getText());
			} else {
				Map<String, Object> map = new LinkedHashMap<String, Object>();
				//进入map迭代
				xmlToJsonMap(element, map);
				jsonMap.put(eleName, map);
			}
		}
	}

	/**
	 * 迭代xml的数组节点到list中
	 * @param elm			要迭代的xml数组节点
	 * @param jsonList		装载结果的list容器
	 */
	@SuppressWarnings("unchecked")
	private static void xmlToJsonList(Element elm, List<Map<String, Object>> jsonList) {
		for (Iterator<Element> it = (Iterator<Element>) elm.elementIterator(); it.hasNext();){
			Element element = (Element) it.next();
			String eleName = element.getName();
			//如果是list下面的节点
			if (XML_LIST_TAG.equals(eleName)) {
				Map<String, Object> map = new LinkedHashMap<String, Object>();
				xmlToJsonMap(element, map);
				jsonList.add(map);
			} else {
				//会进入list迭代的必然包含list节点的保留字标签，如果匹配不到此标签则xml格式错误
				StringBuffer errMsg = new StringBuffer();
				errMsg.append("xml to json error. <").append(eleName).append("> isn't a list key word.");
				throw new CommonSystemException(errMsg.toString());
			}
		}
	}

	/**
	 * json转成xml
	 * @param jsonStr	json格式字符串
	 * @return			xml格式字符串
	 * @throws DocumentException
	 * @throws IOException
	 */
	@SuppressWarnings("unchecked")
	public static String jsonToXml(String jsonStr) throws DocumentException, IOException {
		//将json解析到map中
		Map<String, Object> jsonMap =  JsonUtil.stringToObject(jsonStr, Map.class);
		Document document = DocumentHelper.createDocument();
		Element element = document.addElement("root");
		//将map中的json节点迭代到element中
		jsonToXmlMap(jsonMap, element);
		String retXml = element.asXML();
		return retXml.substring(6, retXml.length()-7);
	}

	/**
	 * 将map中的json节点迭代到element中
	 * @param jsonMap	包含json节点内容的map容器
	 * @param element	装载结果的xml节点类型
	 */
	@SuppressWarnings("unchecked")
	private static void jsonToXmlMap(Map<String, Object> jsonMap, Element element) {
		for (String key : jsonMap.keySet()) {
			Object obj = jsonMap.get(key);
			Element ele = element.addElement(key);
			if (obj instanceof Map) {
				jsonToXmlMap((Map<String, Object>) obj, ele);
			} else if (obj instanceof List) {
				//添加数组属性和数组节点
				ele.addAttribute(XML_LIST_ATTRIBUTE, "true");
				jsonToXmlList((List<Map<String, Object>>) obj, ele);
			} else {
				ele.setText(obj.toString());
			}
		}
	}

	/**
	 * 将list中的json节点迭代到element中
	 * @param jsonList		包含json节点内容的list容器
	 * @param element		装载结果的xml节点类型
	 */
	private static void jsonToXmlList(List<Map<String, Object>> jsonList, Element element) {
		for (Iterator<Map<String, Object>> itr=jsonList.iterator(); itr.hasNext();) {
			Map<String, Object> map = itr.next();
			Element ele = element.addElement(XML_LIST_TAG);
			jsonToXmlMap(map, ele);
		}
	}
}
